package com.nanako.wanxinp2p.account.service.impl;

import com.nanako.wanxinp2p.account.common.AccountErrorCode;
import com.nanako.wanxinp2p.account.entity.Account;
import com.nanako.wanxinp2p.account.mapper.AccountMapper;
import com.nanako.wanxinp2p.account.service.IAccountService;
import com.nanako.wanxinp2p.api.account.model.AccountDTO;
import com.nanako.wanxinp2p.api.account.model.AccountLoginDTO;
import com.nanako.wanxinp2p.api.account.model.AccountRegisterDTO;
import com.nanako.wanxinp2p.common.domain.CommonErrorCode;
import com.nanako.wanxinp2p.common.domain.RestResponse;
import com.nanako.wanxinp2p.common.domain.StatusCode;
import com.nanako.wanxinp2p.common.exception.BusinessException;
import com.nanako.wanxinp2p.common.utils.PasswordUtil;
import com.nanako.wanxinp2p.common.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hmily.annotation.Hmily;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;

@Service
@Slf4j
public class AccountServiceImpl implements IAccountService {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private AccountMapper accountMapper;

    @Value("${sms.enable}")
    private boolean smsEnable;
    @Value("${sms.url}")
    private String url;

    @Override
    public RestResponse getSMSCode(String mobile) {
        HashMap<String, String> map = new HashMap<>();
        map.put("mobile", mobile);
        return restTemplate.postForObject(
                url + "/generate?effectiveTime=300&name=sms",
                map,
                RestResponse.class);
    }


    @Override
    public Integer checkMobile(String mobile, String key, String code) {
          /* 1、远程调用 短信微服务 校验验证码是否正确
              Post请求：
              http://localhost:56085/sailing/verify?name=sms&verificationKey=sms:70ba933b095b4b5c90ee314045fd9003&verificationCode=707339
              根据结果判断验证码校验是否成功，如果失败，则抛出 AccountErrorCode.E_140152 异常

            2、如果验证码正确，还需要根据手机号 去 account 表中查询手机号是否存在
            	如果存在返回 1，否则返回 0
        */

        RestResponse response = restTemplate.postForObject(
                url + "/verify?name=sms&verificationKey=" + key + "&verificationCode=" + code,
                null,
                RestResponse.class);
        if (!response.isSuccessful()) throw new BusinessException(AccountErrorCode.E_140152);
        Account account = accountMapper.getByPhone(mobile);
        return account == null ? 0 : 1;
    }

    @Override
    public AccountDTO login(AccountLoginDTO accountLoginDTO) {
        //1、查询用户，注意此处需要根据前端传递的 AccountLoginDTO的domain做判断：
        //  否则是b端用户，需要根据用户名查询
        String type = accountLoginDTO.getDomain();
        Account account;
        //2、判断用户是否存在，如果不存在，直接抛出 AccountErrorCode.E_130104 异常
        if ("c".equals(type)) {
            //  如果值是 c 表示是c端用户，需要根据手机号查询
            String mobile = accountLoginDTO.getMobile();
            account = accountMapper.selectByMobile(mobile);
            if (account == null) {
                throw new BusinessException(AccountErrorCode.E_130104);
            }
        } else if("b".equals(type)) {
            //  否则是b端用户，需要根据用户名查询
            String username = accountLoginDTO.getUsername();
            account = accountMapper.selectOne(username);
            if (account == null) {
                throw new BusinessException(AccountErrorCode.E_130104);
            }
        } else {
            throw new BusinessException(CommonErrorCode.UNKOWN);
        }
        AccountDTO accountDTO = new AccountDTO();
        BeanUtils.copyProperties(account, accountDTO);
        //3、如果 smsEnable=true ，说明是短信验证码登录，不做密码校验。直接返回
        if (smsEnable){
            return accountDTO;
        }
        //4、验证密码，如果密码错误则抛出 AccountErrorCode.E_130105 异常
        String password = accountLoginDTO.getPassword();
        if (PasswordUtil.verify(accountLoginDTO.getPassword(),
                account.getPassword())) {
            throw new BusinessException(AccountErrorCode.E_130105);
        }
        return accountDTO;
    }

    /**
     * 账户注册
     * @param registerDTO 注册信息
     * @return
     */
    @Override
    @Hmily(confirmMethod = "confirmRegister", cancelMethod = "cancelRegister")
    @Transactional
    public AccountDTO register(AccountRegisterDTO registerDTO) {
        log.info("execute =================>> tryRegister");
        Account account = new Account();
        account.setDomain("c");
        account.setStatus(StatusCode.STATUS_OUT.getCode());
        BeanUtils.copyProperties(registerDTO, account);
        if (StringUtil.isEmpty(registerDTO.getPassword( ))) {
            account.setPassword(PasswordUtil.generate(registerDTO.getPassword()));
        }
        if (smsEnable){
            account.setPassword(PasswordUtil.generate(account.getMobile()));
        }
        accountMapper.register(account);
        AccountDTO accountDTO = new AccountDTO();
        BeanUtils.copyProperties(account, accountDTO);
        return accountDTO;
    }

    @Override
    public void confirmRegister(AccountRegisterDTO registerDTO) {
        log.info("execute =================>> confirmRegister");
    }

    @Override
    public void cancelRegister(AccountRegisterDTO registerDTO) {
        log.info("execute =================>> cancelRegister");
        // 删除账号
        accountMapper.deleteByMobile(registerDTO.getMobile());
    }


    @NotNull
    private static HttpHeaders getHeaders() {
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        return headers;
    }
}
